#ifndef GRAPH_H
#define GRAPH_H
// includes
#include "message.h"

// defines
#define DESTROY_EDGE_LIST(X) { \
    destroyEdgeList(X); \
    X = NULL; \
    }
#define DESTROY_NODE_LIST(X) { \
    destroyNodeList(X); \
    X = NULL; \
    }
#define DESTROY_GRAPH(X) { \
    destroyGraph(X); \
    X = NULL; \
    }
#define DESTROY_NODE(X) { \
    destroyNode(X); \
    X = NULL; \
    }
#define DESTROY_EDGE(X) { \
    destroyEdge(X); \
    X = NULL; \
    }

// typedefs
// structure to hold directional communication channel
typedef struct edge
{
    int from;
    int to;

    struct edge *next;
}Edge;

// structure to hold a list of edges
typedef struct edgeList
{
    int edgeCount;
    Edge *head;
}EdgeList;

// structure to hold a node
typedef struct node
{
    int nodeNumber;
    int data;

    EdgeList *inwardEdges;
    EdgeList *outwardEdges;

    PacketList *inbox;
    PacketList *outbox;
    
    struct node *next;
}Node;

// structure to hold a list of nodes
typedef struct nodeList
{
    int nodeCount;

    Node *head;
}NodeList;

// structure representing the complete graph
typedef struct graph
{
    NodeList *nodes;
    EdgeList *edges;

    void (*nodeComputation)(int roundNumber, Node *node);
}Graph;

// declarations
// creates a edge list holder
EdgeList *createEdgeList();

// creates a nodes list holder
NodeList *createNodeList();

// creates a new graph structure
Graph *createGraph();

// creates a new node structure
Node *createNode();

// creates a new edge structure
Edge *createEdge();

// destroys a edge list holder and deletes the edges in it
void destroyEdgeList(EdgeList *edgeList);

// destroys a node list holder and deletes the nodes in it 
void destroyNodeList(NodeList *nodeList);

// destroys the graph
void destroyGraph(Graph *g);

// destroys given node
void destroyNode(Node *node);

// destroys give edge
void destroyEdge(Edge *edge);

// prints the data values in a graph. used for debugging
void printGraph(Graph *g);

// adds a new node to graph
void addNode (Graph *g, Node *node);

// finds a node with given node number in graph
Node* findNode (Graph *g, int nodeNumber);

// adds an edge to given edge list
void addEdgeToList (EdgeList *edgeList, Edge *edge);

// adds an edge in graph in all apporipriate edge lists
void addEdge (Graph *g, Edge *edge);

// creates a duplicate edge object
Edge* dupEdge (Edge *edge);
#endif /* GRAPH_H */